/**
 * @file fs.h
 * @author LokLiang (lokliang@163.com)
 * @brief 定义文件系统操作接口
 * @version 0.1
 * @date 2023-06-15
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#ifndef __FS_H__
#define __FS_H__

#include "sys_types.h"
#include "list/slist.h"
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Macros --------------------------------------------------------------------*/

#define FS_VOLUME_NAME_LEN 16
#define FS_FILE_NAME_LEN 64
#define FS_PATH_NAME_LEN 0x100

#ifndef FS_O_READ
#define FS_O_READ   0x01
#endif
#ifndef FS_O_WRITE
#define FS_O_WRITE  0x02
#endif
#ifndef FS_O_CREATE
#define FS_O_CREATE 0x10
#endif
#ifndef FS_O_APPEND
#define FS_O_APPEND 0x20
#endif

#ifndef FS_SEEK_SET
#define FS_SEEK_SET 0
#endif
#ifndef FS_SEEK_CUR
#define FS_SEEK_CUR 1
#endif
#ifndef FS_SEEK_END
#define FS_SEEK_END 2
#endif

/* Typedef -------------------------------------------------------------------*/

typedef struct __fs_mount fs_mount_t;

typedef struct
{
    fs_mount_t *mp;
    void *file_hdl;
    uint8_t flags;
} fs_file_t;

typedef struct
{
    fs_mount_t *mp;
    void *dir_hdl;
} fs_dir_t;

typedef enum
{
    FS_INFO_TYPE_DIR,
    FS_INFO_TYPE_FILE,
} fs_file_type_t;

typedef struct
{
    char name[FS_FILE_NAME_LEN + 1];
    fs_file_type_t type;
    uint32_t fsize; // File size
} fs_file_info_t;

typedef struct
{
    uint32_t f_bsize;  // Optimal transfer block size
    uint32_t f_frsize; // Allocation unit size
    uint32_t f_blocks; // Size of FS in f_frsize units
    uint32_t f_bfree;  // Number of free blocks
} fs_statvfs_t;

typedef const char fs_path_t;

typedef struct
{
    int (*open)         (fs_file_t *fp, fs_path_t *path, uint8_t flags);
    int (*close)        (fs_file_t *fp);
    int (*read)         (fs_file_t *fp, void *dest, size_t size);
    int (*write)        (fs_file_t *fp, const void *src, size_t size);
    int (*lseek)        (fs_file_t *fp, int offset, uint8_t whence);
    int (*truncate)     (fs_file_t *fp, int length);
    int (*sync)         (fs_file_t *fp);
    int (*tell)         (fs_file_t *fp);
    int (*opendir)      (fs_dir_t *dp, fs_path_t *path);
    int (*closedir)     (fs_dir_t *dp);
    int (*readdir)      (fs_dir_t *dp, fs_file_info_t *info);
    int (*getcwd)       (fs_mount_t *mp, char *path, int length);
    int (*chdir)        (fs_mount_t *mp, fs_path_t *path);
    int (*mkdir)        (fs_mount_t *mp, fs_path_t *path);
    int (*unlink)       (fs_mount_t *mp, fs_path_t *path);
    int (*rename)       (fs_mount_t *mp, fs_path_t *from, fs_path_t *to);
    int (*stat)         (fs_mount_t *mp, fs_path_t *path, fs_file_info_t *info);
    int (*statvfs)      (fs_mount_t *mp, fs_statvfs_t *stat, const char *volume_name);
    int (*mkfs)         (fs_mount_t *mp, const char *volume_name);
    int (*mount)        (fs_mount_t *mp, const char *volume_name);
    int (*unmount)      (fs_mount_t *mp, const char *volume_name);
} fs_api_t;

typedef struct
{
    uint8_t mount_flag;
} fs_cfg_t;

struct __fs_mount
{
    slist_node_t node;
    char fs_name[FS_VOLUME_NAME_LEN + 1];
    char volume_name[FS_VOLUME_NAME_LEN + 1];
    void *fs_hdl;
    const fs_api_t *api;
    fs_cfg_t cfg;
};

/* Function prototypes -------------------------------------------------------*/

int fs_regist   (const char *fs_name, const fs_api_t *api);
int fs_unregist (const char *fs_name);

const char *getmnt(const char *fs_name, uint8_t num);

int fs_mkfs     (const char *fs_name, const char *volume_name);
int fs_mount    (const char *fs_name, const char *volume_name);
int fs_unmount  (const char *fs_name, const char *volume_name);

int fs_open     (fs_file_t *fp, fs_path_t *path, uint8_t flags);
int fs_close    (fs_file_t *fp);
int fs_read     (fs_file_t *fp, void *dest, size_t size);
int fs_write    (fs_file_t *fp, const void *src, size_t size);
int fs_lseek    (fs_file_t *fp, int offset, uint8_t whence);
int fs_truncate (fs_file_t *fp, int length);
int fs_sync     (fs_file_t *fp);
int fs_tell     (fs_file_t *fp);

int fs_opendir  (fs_dir_t *dp, fs_path_t *path);
int fs_closedir (fs_dir_t *dp);
int fs_readdir  (fs_dir_t *dp, fs_file_info_t *info);

int fs_chdir    (fs_path_t *path);
int fs_getcwd   (char *path, int len);

int fs_mkdir    (fs_path_t *path);
int fs_unlink   (fs_path_t *path);
int fs_rename   (fs_path_t *from, fs_path_t *to);
int fs_stat     (fs_path_t *path, fs_file_info_t *info);
int fs_statvfs  (const char *fs_name, const char *volume_name, fs_statvfs_t *stat);

/* Interface -----------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif
